/*
 * @lc app=leetcode.cn id=146 lang=javascript
 *
 * [146] LRU 缓存
 */

// @lc code=start
function DLinkedNode(key, val) {
  this.key = key;
  this.val = val;
  this.pre = null;
  this.next = null;
}
/**
 * @param {number} capacity
 */
var LRUCache = function (capacity) {
  this.capacity = capacity;
  this.size = 0;
  this.map = new Map();
  this.dummyHead = new DLinkedNode();
  this.dummyTail = new DLinkedNode();
  this.dummyHead.next = this.dummyTail;
  this.dummyTail.pre = this.dummyHead;
};

LRUCache.prototype.deleteFromList = function (node) {
  const pre = node.pre;
  const next = node.next;
  pre.next = next;
  next.pre = pre;
};

LRUCache.prototype.addToHead = function (node) {
  const next = this.dummyHead.next;
  node.pre = this.dummyHead;
  node.next = next;
  this.dummyHead.next = node;
  next.pre = node;
};

LRUCache.prototype.moveToHead = function (node) {
  this.deleteFromList(node);
  this.addToHead(node);
};

LRUCache.prototype.deleteFromLRU = function () {
  const tail = this.dummyTail.pre;
  this.deleteFromList(tail);
  this.map.delete(tail.key);
  this.size--;
};

/**
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function (key) {
  const node = this.map.get(key);
  if (!node) return -1;
  this.moveToHead(node);
  return node.val;
};

/**
 * @param {number} key
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function (key, value) {
  const node = this.map.get(key);
  if (node) {
    node.val = value;
    this.moveToHead(node);
    return;
  }
  const newNode = new DLinkedNode(key, value);
  this.addToHead(newNode);
  this.map.set(key, newNode);
  this.size++;
  if (this.size > this.capacity) {
    this.deleteFromLRU();
  }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * var obj = new LRUCache(capacity)
 * var param_1 = obj.get(key)
 * obj.put(key,value)
 */
// @lc code=end
